package com.android.accessibility.function;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import android.os.FileObserver;

import com.android.accessibility.utils.Log;

public class RecursiveFileObserver extends FileObserver {

    /** Only modification events */
    public static int CHANGES_ONLY = CREATE | DELETE | CLOSE_WRITE
            | DELETE_SELF | MOVE_SELF | MOVED_FROM | MOVED_TO;

    List<SingleFileObserver> mObservers;
    String mPath;
    int mMask;

    public RecursiveFileObserver(String path) {
        this(path, ALL_EVENTS);
    }

    public RecursiveFileObserver(String path, int mask) {
        super(path, mask);
        mPath = path;
        mMask = mask;
    }

    public void startWatchingByUser() {
        if (mObservers != null)
            return;

        mObservers = new ArrayList<SingleFileObserver>();
        Stack<String> stack = new Stack<String>();
        stack.push(mPath);

        while (!stack.isEmpty()) {
            String parent = (String) stack.pop();
            Log.d(Log.TAG, "mMask : " + mMask);
            mObservers.add(new SingleFileObserver(parent, mMask));
            File path = new File(parent);
            File[] files = path.listFiles();
            if (null == files)
                continue;
            for (File f : files) {
                if (f.isDirectory() && !f.getName().equals(".")
                        && !f.getName().equals("..")) {
                    stack.push(f.getPath());
                }
            }
        }

        for (int i = 0; i < mObservers.size(); i++) {
            SingleFileObserver sfo = (SingleFileObserver) mObservers.get(i);
            Log.d(Log.TAG, "ob : " + sfo.getPath());
            sfo.startWatching();
        }
    };

    public void stopWatchingByUser() {
        if (mObservers == null)
            return;

        for (int i = 0; i < mObservers.size(); i++) {
            SingleFileObserver sfo = (SingleFileObserver) mObservers.get(i);
            Log.d(Log.TAG, "ob : " + sfo.getPath());
            sfo.stopWatching();
        }

        mObservers.clear();
        mObservers = null;
    };

    @Override
    public void onEvent(int event, String path) {
        switch (event) {
        case FileObserver.ACCESS:
            Log.d(Log.TAG, "ACCESS: " + path);
            break;
        case FileObserver.ATTRIB:
            Log.d(Log.TAG, "ATTRIB: " + path);
            break;
        case FileObserver.CLOSE_NOWRITE:
            Log.d(Log.TAG, "CLOSE_NOWRITE: " + path);
            break;
        case FileObserver.CLOSE_WRITE:
            Log.d(Log.TAG, "CLOSE_WRITE: " + path);
            break;
        case FileObserver.CREATE:
            Log.d(Log.TAG, "CREATE: " + path);
            break;
        case FileObserver.DELETE:
            Log.d(Log.TAG, "DELETE: " + path);
            break;
        case FileObserver.DELETE_SELF:
            Log.d(Log.TAG, "DELETE_SELF: " + path);
            break;
        case FileObserver.MODIFY:
            Log.d(Log.TAG, "MODIFY: " + path);
            break;
        case FileObserver.MOVE_SELF:
            Log.d(Log.TAG, "MOVE_SELF: " + path);
            break;
        case FileObserver.MOVED_FROM:
            Log.d(Log.TAG, "MOVED_FROM: " + path);
            break;
        case FileObserver.MOVED_TO:
            Log.d(Log.TAG, "MOVED_TO: " + path);
            break;
        case FileObserver.OPEN:
            Log.d(Log.TAG, "OPEN: " + path);
            break;
        default:
            Log.d(Log.TAG, "DEFAULT(" + event + " : " + path);
            break;
        }
    }

    /**
     * Monitor single directory and dispatch all events to its parent, with full
     * path.
     */
    class SingleFileObserver extends FileObserver {
        String mPath;

        public SingleFileObserver(String path) {
            this(path, ALL_EVENTS);
            mPath = path;
        }

        public SingleFileObserver(String path, int mask) {
            super(path, mask);
            mPath = path;
        }

        @Override
        public void onEvent(int event, String path) {
            Log.d(Log.TAG, "event : " + event);
            String newPath = mPath + "/" + path;
            RecursiveFileObserver.this.onEvent(event, newPath);
        }

        public String getPath() {
            return mPath;
        }
    }
}
